#include <stdio.h>

#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

#include "ysh.h"
#include "sig_handle.h"
#include "jc.h"
#include "pool.h"
#include "encap.h"


char sh_info_str[LINE_BUF_SIZE];
void sh_info(char *info)
{
#ifdef DEBUG
    // May later catenate to prompt string.
    fprintf(stderr, "%s\n", info);
#endif
}

void jc_info(int jid, char *status, char *cmd_string)
{
    prompt_string.len += sprintf(&prompt_string.str[prompt_string.len], "[%d]+%4s%s%8s%s\n", jid, "", status, "",  cmd_string);
}

static void sh_sigchld(int signo)
{
    /*
    pid_t pid;
    int stat_val;
    int w_signo;
    Process *t_p;
    // trick here needed.
    pid = ec_wait(&stat_val);
    if (WIFEXITED(stat_val)) {
        jc_status = WEXITSTATUS(stat_val);
        printf("SIGCHLD: %d\n", pid);
        delete_p(pid);
        if (WIFSIGNALED(stat_val)) {
            w_signo = WTERMSIG(stat_val);
            sprintf(sh_info_str, "Process %d is terminated by signal %d.", pid, w_signo);
            sh_info(sh_info_str);
        }
    }
    else if (WIFSTOPPED(stat_val)) {
        w_signo = WSTOPSIG(stat_val);
        t_p = find_p(pid);
        t_p->status = JS_STOPPED;
        sprintf(sh_info_str, "Process %d is currently stopped by signal %d.", pid, w_signo);
        sh_info(sh_info_str);
    }
#ifdef WIFCONTINUED
    else if(WIFCONTINUED(stat_val)) {
        t_p = find_p(pid);
        t_p->status = JS_RUNNING;
        sprintf(sh_info_str, "Process %d is currently continued after being stopped.", pid);
        sh_info(sh_info_str);
    }
#endif
    else {
        sprintf(sh_info_str, "Unexpected status 0x%x when waiting process %d.\n", stat_val, pid);
        sh_info(sh_info_str);
    }
    */
}

static void sh_sig_tstp_int(int signo)
{
    pid_t fgpgrp;
    void (*p)(int);
    fgpgrp = ec_tcgetpgrp(TERM_FILEDES);
    printf("%s\n", sys_siglist[signo]);
    if (fgpgrp != ysh_pid) {
        ec_kill(-fgpgrp, signo);
        p = signal(SIGTTOU, SIG_IGN);
        ec_tcsetpgrp(TERM_FILEDES, ysh_pid);
        signal(SIGTTOU, p);
    }
}

void sig_handle(int signo)
{
    switch (signo) {
        case SIGCHLD:
            sh_sigchld(signo);
            break;
        case SIGTSTP:
            sh_sig_tstp_int(signo);
            break;
        case SIGINT:
#ifdef DEBUG
            printf("DEBUG MODE.\n");
            restore_back();
#else
            sh_sig_tstp_int(signo);
#endif
            break;
        default:
            break;
    }
}

void sig_reset(void)
{
    // sigset_t maybe suitable.
    signal(SIGTTOU, SIG_DFL);
    if (signal(SIGTSTP, SIG_IGN) != SIG_DFL) {
        signal(SIGTSTP, SIG_IGN);
    }
    signal(SIGTSTP, SIG_DFL);
    signal(SIGCHLD, SIG_DFL);
    signal(SIGINT, SIG_DFL);
}

void sig_init(void)
{
    struct termios term;

    signal(SIGTTOU, SIG_IGN);                                   // Also for tcsetattr.
    signal(SIGCHLD, SIG_DFL);                                   // Unix - Frequently asked questions: How do I get rid of zombie processes that persevre.
    signal(SIGTSTP, SIG_IGN);
    signal(SIGINT, SIG_IGN);                                  // Ctrl_C

    // In practice shells often override the default stop action so 
    // that the background jobs deliver their output to the controlling 
    // terminal by default.
    // TOSTOP should be taken special attention.
    ec_tcgetattr(TERM_FILEDES, &term);
    term.c_lflag |= TOSTOP;
    ec_tcsetattr(TERM_FILEDES, TCSADRAIN, &term, TOSTOP);
}

